package ch.myDungeons.io;

import java.util.ArrayList;

import ch.myDungeons.characters.NPC;
import ch.myDungeons.characters.Person;
import ch.myDungeons.characters.Player;
import ch.myDungeons.game.Inventory;
import ch.myDungeons.game.Map;
import ch.myDungeons.game.Tile;
import ch.myDungeons.game.Inventory.BagSlot;
import ch.myDungeons.gameObjects.Potion;
import ch.myDungeons.game.MyDungeon;


/**
 * A static class to generate maps and populate with items
 * @author Grii
 *
 */
public class MapGenerator {
	
	/** creates a new map with random obstacles. obstacleDensitiy in percent */
	public static Map createMapWithRandomObstacles(int sizeX, int sizeY, int obstacleDensitiy){
		Map map = new Map(sizeX, sizeY);
		for (int i = 0; i < map.tiles.length; i++) {
			for (int j = 0; j < map.tiles[i].length; j++) {
				if (Math.random()*100 < obstacleDensitiy) {
					map.tiles[i][j].accessible = false;
				} else {
					map.tiles[i][j].accessible = true;
				}
			}
		}
		addStairs(map);
		return map;
	}
	
	/** creates a new map with normal rooms */
	public static Map createMapWithRooms(int sizeX, int sizeY, int roomSize, int roomRandomSize, int roomCount, int roomRandomCount){
		Map map = new Map(sizeX, sizeY);
		int roomCountFinal = (int)(roomCount+Math.random()*roomRandomCount);
		
		for (int i = 0; i < map.tiles.length; i++) {
			for (int j = 0; j < map.tiles[i].length; j++) {
				map.tiles[i][j].accessible = false;
			}
		}
		map = addRoom(map, true, roomSize, roomRandomSize);
		for (int i = 1; i < roomCountFinal; i++) {
			map = addRoom(map, false, roomSize, roomRandomSize);
		}
		addStairs(map);
		return map;
	}
	private static Map addRoom(Map map, boolean first, int roomSize, int roomRandomSize){
		int roomSizeX = 2*(roomSize+(int)(Math.random()*roomRandomSize));
		int roomSizeY = roomSize+(int)(Math.random()*roomRandomSize);
		if (first) {
			int posX = (int)((map.tiles.length-roomSizeX)*Math.random());
			int posY = (int)((map.tiles[0].length-roomSizeY)*Math.random());
			for (int i = posX; i < roomSizeX + posX; i++) {
				for (int j = posY; j < roomSizeY + posY; j++) {
					map.tiles[i][j].accessible = true;
				}
			}
		} else {
			int startX = (int)((map.tiles.length)*Math.random());
			int startY = (int)((map.tiles[0].length)*Math.random());
			while(!map.tiles[startX][startY].accessible){
				startX = (int)((map.tiles.length)*Math.random());
				startY = (int)((map.tiles[0].length)*Math.random());
			}
			int pathLength = 10 + (int)(30*Math.random());
			int dir = 0;
			int targetX = -1;
			int targetY = -1;
			int posX = targetX;
			int posY = targetY;
			
			while(!map.checkIsOnMap(targetX, targetY) || !map.checkIsOnMap(posX, posY) || !map.checkIsOnMap(posX + roomSizeX, posY + roomSizeY)){
				dir = (int)(4*Math.random());
				pathLength = 3 + (int)(20*Math.random());
				int tmpX = startX;
				int tmpY = startY;
				for (int i = 0; i < pathLength; i++) {
					int[] tmpPos = map.getPostitionFromDirection(dir, tmpX, tmpY);
					tmpX = tmpPos[0];
					tmpY = tmpPos[1];
				}
				targetX = tmpX;
				targetY = tmpY;
				posX = targetX - (int)(Math.random()*roomSizeX);
				posY = targetY - (int)(Math.random()*roomSizeY);
			}
			int tmpX = startX;
			int tmpY = startY;
			for (int i = 0; i < pathLength; i++) {
				map.tiles[tmpX][tmpY].accessible = true;
				int[] tmpPos = map.getPostitionFromDirection(dir, tmpX, tmpY);
				tmpX = tmpPos[0];
				tmpY = tmpPos[1];
			}
			
			for (int i = posX; i < roomSizeX + posX; i++) {
				for (int j = posY; j < roomSizeY + posY; j++) {
					if (map.checkIsOnMap(i, j)) {
						map.tiles[i][j].accessible = true;
					}
				}
			}
		}
		return map;
	}
	
	
	/** Adds random stairs to the map */
	private static Map addStairs(Map map){
		int tmpX = (int)(Math.random()*map.tiles.length);
		int tmpY = (int)(Math.random()*map.tiles[0].length);
		while(!map.tiles[tmpX][tmpY].accessible){
			tmpX = (int)(Math.random()*map.tiles.length);
			tmpY = (int)(Math.random()*map.tiles[0].length);
		}
		map.tiles[tmpX][tmpY].isStairsUp = true;
		
		while(!map.tiles[tmpX][tmpY].accessible || map.tiles[tmpX][tmpY].isStairsUp){
			tmpX = (int)(Math.random()*map.tiles.length);
			tmpY = (int)(Math.random()*map.tiles[0].length);
		}
		map.tiles[tmpX][tmpY].isStairsDown = true;
		return map;
	}
	
	/** Adds some random items to the map */
	public static Map addSomeItems(Map map){
		for (int i = 0; i < map.tiles.length; i++) {
			for (int j = 0; j < map.tiles[i].length; j++) {
				if (!map.checkObstacle(i, j) && !map.tiles[i][j].isStairsDown && !map.tiles[i][j].isStairsUp) {
					if (Math.random()*1000 < 10) {
						if (Math.random()*100 < 50) {
							map.tiles[i][j].inventory.addItem(ch.myDungeons.io.ItemGenerator.createArmorFromRating((int)(Math.random()*(5+MyDungeon.game.mapLevel))));
						} else {
							map.tiles[i][j].inventory.addItem(ch.myDungeons.io.ItemGenerator.createWeaponFromRating((int)(Math.random()*(5+MyDungeon.game.mapLevel))));
						}
					}
					if (Math.random()*1000 < 10) {
						map.tiles[i][j].inventory.addItem(new Potion.HealthPotion(""));
					}
				}
			}
		}
		return map;
	}
	
	
	/** Loads a map from a string 
	 * @deprecated */
	@Deprecated
	public static Map createMapFromSavedString(String mapString){
		
		String[] lineStrings = mapString.split("<MAPLINE>");
		int xSize = Integer.parseInt(lineStrings[0].split("<TILE>")[0]);
		int ySize = Integer.parseInt(lineStrings[0].split("<TILE>")[1]);
		Tile[][] tiles = new Tile[xSize][ySize];
		
		ArrayList<NPC> enemies = new ArrayList<NPC>();
		ArrayList<NPC> allies = new ArrayList<NPC>();
		
		Map loadedMap = new Map(xSize, ySize);
		loadedMap.tiles = tiles;
		
		for (int y = 0; y < ySize; y++) {
			String tileStrings[] = lineStrings[y+1].split("<TILE>");
			for (int x = 0; x < xSize; x++) {
				
				Tile tmpTile = createTileFromSavedString(tileStrings[x+1], x, y, loadedMap);
				tiles[x][y] = tmpTile;
				
				if (tmpTile.personOnTheTile != null) {
					if (tmpTile.personOnTheTile instanceof Player) {
						MyDungeon.game.setPlayer((Player) tmpTile.personOnTheTile);
					} else {
						if (tmpTile.personOnTheTile.isFriendly()) {
							allies.add((NPC) tmpTile.personOnTheTile);
						} else {
							enemies.add((NPC) tmpTile.personOnTheTile);
						}
					}
				}
			}
		}
		
		loadedMap.enemies = enemies;
		loadedMap.allies = allies;
		return loadedMap;
	}
	
	/** Loads a tile from a string 
	 * @deprecated */
	@Deprecated
	private static Tile createTileFromSavedString(String tileString, int posX, int posY, Map map){
		String[] infoStrings = tileString.split("<TILEINFO>");
		
		boolean accessible = infoStrings[0].equals("true");
		boolean stairsUp = infoStrings[1].equals("true");
		boolean stairsDown = infoStrings[2].equals("true");
		BagSlot[] items = ItemGenerator.createItemsFormString(infoStrings[3]);
		Person personOnTheTile = null;
		if (!infoStrings[4].equals("null")) {
			personOnTheTile = PersonGenerator.createPersonFromSavedString(infoStrings[4], map);
			personOnTheTile.setPosX(posX);
			personOnTheTile.setPosY(posY);
		}
		
		Tile loadedTile = new Tile(accessible, posX, posY);
		loadedTile.isStairsUp = stairsUp;
		loadedTile.isStairsDown = stairsDown;
		loadedTile.inventory = new Inventory();
		for (int i = 0; i < items.length; i++) {
			loadedTile.inventory.addItem(items[i]);
		}
		
		loadedTile.personOnTheTile = personOnTheTile;
		return loadedTile;
	}
}
